home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / lib / ruby / 1.8 / rational.rb < prev    next >
Text File  |  2008-05-24  |  12KB  |  565 lines

  1. #
  2. #   rational.rb -
  3. #       $Release Version: 0.5 $
  4. #       $Revision: 1.7 $
  5. #       $Date: 1999/08/24 12:49:28 $
  6. #       by Keiju ISHITSUKA(SHL Japan Inc.)
  7. #
  8. # Documentation by Kevin Jackson and Gavin Sinclair.
  9. # When you <tt>require 'rational'</tt>, all interactions between numbers
  10. # potentially return a rational result.  For example:
  11. #
  12. #   1.quo(2)              # -> 0.5
  13. #   require 'rational'
  14. #   1.quo(2)              # -> Rational(1,2)
  15. # See Rational for full documentation.
  16. #
  17.  
  18.  
  19. #
  20. # Creates a Rational number (i.e. a fraction).  +a+ and +b+ should be Integers:
  21. #   Rational(1,3)           # -> 1/3
  22. #
  23. # Note: trying to construct a Rational with floating point or real values
  24. # produces errors:
  25. #
  26. #   Rational(1.1, 2.3)      # -> NoMethodError
  27. #
  28. def Rational(a, b = 1)
  29.   if a.kind_of?(Rational) && b == 1
  30.     a
  31.   else
  32.     Rational.reduce(a, b)
  33.   end
  34. end
  35.  
  36. #
  37. # Rational implements a rational class for numbers.
  38. #
  39. # <em>A rational number is a number that can be expressed as a fraction p/q
  40. # where p and q are integers and q != 0.  A rational number p/q is said to have
  41. # numerator p and denominator q.  Numbers that are not rational are called
  42. # irrational numbers.</em> (http://mathworld.wolfram.com/RationalNumber.html)
  43. #
  44. # To create a Rational Number:
  45. #   Rational(a,b)             # -> a/b
  46. #   Rational.new!(a,b)        # -> a/b
  47. #
  48. # Examples:
  49. #   Rational(5,6)             # -> 5/6
  50. #   Rational(5)               # -> 5/1
  51. # Rational numbers are reduced to their lowest terms:
  52. #   Rational(6,10)            # -> 3/5
  53. #
  54. # But not if you use the unusual method "new!":
  55. #   Rational.new!(6,10)       # -> 6/10
  56. #
  57. # Division by zero is obviously not allowed:
  58. #   Rational(3,0)             # -> ZeroDivisionError
  59. #
  60. class Rational < Numeric
  61.   @RCS_ID='-$Id: rational.rb,v 1.7 1999/08/24 12:49:28 keiju Exp keiju $-'
  62.  
  63.   #
  64.   # Reduces the given numerator and denominator to their lowest terms.  Use
  65.   # Rational() instead.
  66.   #
  67.   def Rational.reduce(num, den = 1)
  68.     raise ZeroDivisionError, "denominator is zero" if den == 0
  69.  
  70.     if den < 0
  71.       num = -num
  72.       den = -den
  73.     end
  74.     gcd = num.gcd(den)
  75.     num = num.div(gcd)
  76.     den = den.div(gcd)
  77.     if den == 1 && defined?(Unify)
  78.       num
  79.     else
  80.       new!(num, den)
  81.     end
  82.   end
  83.  
  84.   #
  85.   # Implements the constructor.  This method does not reduce to lowest terms or
  86.   # check for division by zero.  Therefore #Rational() should be preferred in
  87.   # normal use.
  88.   #
  89.   def Rational.new!(num, den = 1)
  90.     new(num, den)
  91.   end
  92.  
  93.   private_class_method :new
  94.  
  95.   #
  96.   # This method is actually private.
  97.   #
  98.   def initialize(num, den)
  99.     if den < 0
  100.       num = -num
  101.       den = -den
  102.     end
  103.     if num.kind_of?(Integer) and den.kind_of?(Integer)
  104.       @numerator = num
  105.       @denominator = den
  106.     else
  107.       @numerator = num.to_i
  108.       @denominator = den.to_i
  109.     end
  110.   end
  111.  
  112.   #
  113.   # Returns the addition of this value and +a+.
  114.   #
  115.   # Examples:
  116.   #   r = Rational(3,4)      # -> Rational(3,4)
  117.   #   r + 1                  # -> Rational(7,4)
  118.   #   r + 0.5                # -> 1.25
  119.   #
  120.   def + (a)
  121.     if a.kind_of?(Rational)
  122.       num = @numerator * a.denominator
  123.       num_a = a.numerator * @denominator
  124.       Rational(num + num_a, @denominator * a.denominator)
  125.     elsif a.kind_of?(Integer)
  126.       self + Rational.new!(a, 1)
  127.     elsif a.kind_of?(Float)
  128.       Float(self) + a
  129.     else
  130.       x, y = a.coerce(self)
  131.       x + y
  132.     end
  133.   end
  134.  
  135.   #
  136.   # Returns the difference of this value and +a+.
  137.   # subtracted.
  138.   #
  139.   # Examples:
  140.   #   r = Rational(3,4)    # -> Rational(3,4)
  141.   #   r - 1                # -> Rational(-1,4)
  142.   #   r - 0.5              # -> 0.25
  143.   #
  144.   def - (a)
  145.     if a.kind_of?(Rational)
  146.       num = @numerator * a.denominator
  147.       num_a = a.numerator * @denominator
  148.       Rational(num - num_a, @denominator*a.denominator)
  149.     elsif a.kind_of?(Integer)
  150.       self - Rational.new!(a, 1)
  151.     elsif a.kind_of?(Float)
  152.       Float(self) - a
  153.     else
  154.       x, y = a.coerce(self)
  155.       x - y
  156.     end
  157.   end
  158.  
  159.   #
  160.   # Returns the product of this value and +a+.
  161.   #
  162.   # Examples:
  163.   #   r = Rational(3,4)    # -> Rational(3,4)
  164.   #   r * 2                # -> Rational(3,2)
  165.   #   r * 4                # -> Rational(3,1)
  166.   #   r * 0.5              # -> 0.375
  167.   #   r * Rational(1,2)    # -> Rational(3,8)
  168.   #
  169.   def * (a)
  170.     if a.kind_of?(Rational)
  171.       num = @numerator * a.numerator
  172.       den = @denominator * a.denominator
  173.       Rational(num, den)
  174.     elsif a.kind_of?(Integer)
  175.       self * Rational.new!(a, 1)
  176.     elsif a.kind_of?(Float)
  177.       Float(self) * a
  178.     else
  179.       x, y = a.coerce(self)
  180.       x * y
  181.     end
  182.   end
  183.  
  184.   #
  185.   # Returns the quotient of this value and +a+.
  186.   #   r = Rational(3,4)    # -> Rational(3,4)
  187.   #   r / 2                # -> Rational(3,8)
  188.   #   r / 2.0              # -> 0.375
  189.   #   r / Rational(1,2)    # -> Rational(3,2)
  190.   #
  191.   def / (a)
  192.     if a.kind_of?(Rational)
  193.       num = @numerator * a.denominator
  194.       den = @denominator * a.numerator
  195.       Rational(num, den)
  196.     elsif a.kind_of?(Integer)
  197.       raise ZeroDivisionError, "division by zero" if a == 0
  198.       self / Rational.new!(a, 1)
  199.     elsif a.kind_of?(Float)
  200.       Float(self) / a
  201.     else
  202.       x, y = a.coerce(self)
  203.       x / y
  204.     end
  205.   end
  206.  
  207.   #
  208.   # Returns this value raised to the given power.
  209.   #
  210.   # Examples:
  211.   #   r = Rational(3,4)    # -> Rational(3,4)
  212.   #   r ** 2               # -> Rational(9,16)
  213.   #   r ** 2.0             # -> 0.5625
  214.   #   r ** Rational(1,2)   # -> 0.866025403784439
  215.   #
  216.   def ** (other)
  217.     if other.kind_of?(Rational)
  218.       Float(self) ** other
  219.     elsif other.kind_of?(Integer)
  220.       if other > 0
  221.     num = @numerator ** other
  222.     den = @denominator ** other
  223.       elsif other < 0
  224.     num = @denominator ** -other
  225.     den = @numerator ** -other
  226.       elsif other == 0
  227.     num = 1
  228.     den = 1
  229.       end
  230.       Rational.new!(num, den)
  231.     elsif other.kind_of?(Float)
  232.       Float(self) ** other
  233.     else
  234.       x, y = other.coerce(self)
  235.       x ** y
  236.     end
  237.   end
  238.  
  239.   def div(other)
  240.     (self / other).floor
  241.   end
  242.  
  243.   #
  244.   # Returns the remainder when this value is divided by +other+.
  245.   #
  246.   # Examples:
  247.   #   r = Rational(7,4)    # -> Rational(7,4)
  248.   #   r % Rational(1,2)    # -> Rational(1,4)
  249.   #   r % 1                # -> Rational(3,4)
  250.   #   r % Rational(1,7)    # -> Rational(1,28)
  251.   #   r % 0.26             # -> 0.19
  252.   #
  253.   def % (other)
  254.     value = (self / other).floor
  255.     return self - other * value
  256.   end
  257.  
  258.   #
  259.   # Returns the quotient _and_ remainder.
  260.   #
  261.   # Examples:
  262.   #   r = Rational(7,4)        # -> Rational(7,4)
  263.   #   r.divmod Rational(1,2)   # -> [3, Rational(1,4)]
  264.   #
  265.   def divmod(other)
  266.     value = (self / other).floor
  267.     return value, self - other * value
  268.   end
  269.  
  270.   #
  271.   # Returns the absolute value.
  272.   #
  273.   def abs
  274.     if @numerator > 0
  275.       self
  276.     else
  277.       Rational.new!(-@numerator, @denominator)
  278.     end
  279.   end
  280.  
  281.   #
  282.   # Returns +true+ iff this value is numerically equal to +other+.
  283.   #
  284.   # But beware:
  285.   #   Rational(1,2) == Rational(4,8)          # -> true
  286.   #   Rational(1,2) == Rational.new!(4,8)     # -> false
  287.   #
  288.   # Don't use Rational.new!
  289.   #
  290.   def == (other)
  291.     if other.kind_of?(Rational)
  292.       @numerator == other.numerator and @denominator == other.denominator
  293.     elsif other.kind_of?(Integer)
  294.       self == Rational.new!(other, 1)
  295.     elsif other.kind_of?(Float)
  296.       Float(self) == other
  297.     else
  298.       other == self
  299.     end
  300.   end
  301.  
  302.   #
  303.   # Standard comparison operator.
  304.   #
  305.   def <=> (other)
  306.     if other.kind_of?(Rational)
  307.       num = @numerator * other.denominator
  308.       num_a = other.numerator * @denominator
  309.       v = num - num_a
  310.       if v > 0
  311.     return 1
  312.       elsif v < 0
  313.     return  -1
  314.       else
  315.     return 0
  316.       end
  317.     elsif other.kind_of?(Integer)
  318.       return self <=> Rational.new!(other, 1)
  319.     elsif other.kind_of?(Float)
  320.       return Float(self) <=> other
  321.     elsif defined? other.coerce
  322.       x, y = other.coerce(self)
  323.       return x <=> y
  324.     else
  325.       return nil
  326.     end
  327.   end
  328.  
  329.   def coerce(other)
  330.     if other.kind_of?(Float)
  331.       return other, self.to_f
  332.     elsif other.kind_of?(Integer)
  333.       return Rational.new!(other, 1), self
  334.     else
  335.       super
  336.     end
  337.   end
  338.  
  339.   #
  340.   # Converts the rational to an Integer.  Not the _nearest_ integer, the
  341.   # truncated integer.  Study the following example carefully:
  342.   #   Rational(+7,4).to_i             # -> 1
  343.   #   Rational(-7,4).to_i             # -> -1
  344.   #   (-1.75).to_i                    # -> -1
  345.   #
  346.   # In other words:
  347.   #   Rational(-7,4) == -1.75                 # -> true
  348.   #   Rational(-7,4).to_i == (-1.75).to_i     # -> true
  349.   #
  350.  
  351.  
  352.   def floor()
  353.     @numerator.div(@denominator)
  354.   end
  355.  
  356.   def ceil()
  357.     -((-@numerator).div(@denominator))
  358.   end
  359.  
  360.   def truncate()
  361.     if @numerator < 0
  362.       return -((-@numerator).div(@denominator))
  363.     end
  364.     @numerator.div(@denominator)
  365.   end
  366.  
  367.   alias_method :to_i, :truncate
  368.  
  369.   def round()
  370.     if @numerator < 0
  371.       num = -@numerator
  372.       num = num * 2 + @denominator
  373.       den = @denominator * 2
  374.       -(num.div(den))
  375.     else
  376.       num = @numerator * 2 + @denominator
  377.       den = @denominator * 2
  378.       num.div(den)
  379.     end
  380.   end
  381.  
  382.   #
  383.   # Converts the rational to a Float.
  384.   #
  385.   def to_f
  386.     @numerator.to_f/@denominator.to_f
  387.   end
  388.  
  389.   #
  390.   # Returns a string representation of the rational number.
  391.   #
  392.   # Example:
  393.   #   Rational(3,4).to_s          #  "3/4"
  394.   #   Rational(8).to_s            #  "8"
  395.   #
  396.   def to_s
  397.     if @denominator == 1
  398.       @numerator.to_s
  399.     else
  400.       @numerator.to_s+"/"+@denominator.to_s
  401.     end
  402.   end
  403.  
  404.   #
  405.   # Returns +self+.
  406.   #
  407.   def to_r
  408.     self
  409.   end
  410.  
  411.   #
  412.   # Returns a reconstructable string representation:
  413.   #
  414.   #   Rational(5,8).inspect     # -> "Rational(5, 8)"
  415.   #
  416.   def inspect
  417.     sprintf("Rational(%s, %s)", @numerator.inspect, @denominator.inspect)
  418.   end
  419.  
  420.   #
  421.   # Returns a hash code for the object.
  422.   #
  423.   def hash
  424.     @numerator.hash ^ @denominator.hash
  425.   end
  426.  
  427.   attr :numerator
  428.   attr :denominator
  429.  
  430.   private :initialize
  431. end
  432.  
  433. class Integer
  434.   #
  435.   # In an integer, the value _is_ the numerator of its rational equivalent.
  436.   # Therefore, this method returns +self+.
  437.   #
  438.   def numerator
  439.     self
  440.   end
  441.  
  442.   #
  443.   # In an integer, the denominator is 1.  Therefore, this method returns 1.
  444.   #
  445.   def denominator
  446.     1
  447.   end
  448.  
  449.   #
  450.   # Returns a Rational representation of this integer.
  451.   #
  452.   def to_r
  453.     Rational(self, 1)
  454.   end
  455.  
  456.   #
  457.   # Returns the <em>greatest common denominator</em> of the two numbers (+self+
  458.   # and +n+).
  459.   #
  460.   # Examples:
  461.   #   72.gcd 168           # -> 24
  462.   #   19.gcd 36            # -> 1
  463.   #
  464.   # The result is positive, no matter the sign of the arguments.
  465.   #
  466.   def gcd(other)
  467.     min = self.abs
  468.     max = other.abs
  469.     while min > 0
  470.       tmp = min
  471.       min = max % min
  472.       max = tmp
  473.     end
  474.     max
  475.   end
  476.  
  477.   #
  478.   # Returns the <em>lowest common multiple</em> (LCM) of the two arguments
  479.   # (+self+ and +other+).
  480.   #
  481.   # Examples:
  482.   #   6.lcm 7        # -> 42
  483.   #   6.lcm 9        # -> 18
  484.   #
  485.   def lcm(other)
  486.     if self.zero? or other.zero?
  487.       0
  488.     else
  489.       (self.div(self.gcd(other)) * other).abs
  490.     end
  491.   end
  492.  
  493.   #
  494.   # Returns the GCD _and_ the LCM (see #gcd and #lcm) of the two arguments
  495.   # (+self+ and +other+).  This is more efficient than calculating them
  496.   # separately.
  497.   #
  498.   # Example:
  499.   #   6.gcdlcm 9     # -> [3, 18]
  500.   #
  501.   def gcdlcm(other)
  502.     gcd = self.gcd(other)
  503.     if self.zero? or other.zero?
  504.       [gcd, 0]
  505.     else
  506.       [gcd, (self.div(gcd) * other).abs]
  507.     end
  508.   end
  509. end
  510.  
  511. class Fixnum
  512.   remove_method :quo
  513.  
  514.   # If Rational is defined, returns a Rational number instead of a Float.
  515.   def quo(other)
  516.     Rational.new!(self, 1) / other
  517.   end
  518.   alias rdiv quo
  519.  
  520.   # Returns a Rational number if the result is in fact rational (i.e. +other+ < 0).
  521.   def rpower (other)
  522.     if other >= 0
  523.       self.power!(other)
  524.     else
  525.       Rational.new!(self, 1)**other
  526.     end
  527.   end
  528.  
  529. end
  530.  
  531. class Bignum
  532.   remove_method :quo
  533.  
  534.   # If Rational is defined, returns a Rational number instead of a Float.
  535.   def quo(other)
  536.     Rational.new!(self, 1) / other
  537.   end
  538.   alias rdiv quo
  539.  
  540.   # Returns a Rational number if the result is in fact rational (i.e. +other+ < 0).
  541.   def rpower (other)
  542.     if other >= 0
  543.       self.power!(other)
  544.     else
  545.       Rational.new!(self, 1)**other
  546.     end
  547.   end
  548.  
  549. end
  550.  
  551. unless defined? 1.power!
  552.   class Fixnum
  553.     alias power! **
  554.     alias ** rpower
  555.   end
  556.   class Bignum
  557.     alias power! **
  558.     alias ** rpower
  559.   end
  560. end
  561.